#
# Chat State Notifications (XEP-0085) (only <active/> and <composing/>) support.
#

namespace eval chatstate {
    disco::register_feature $::NS(chatstate)
}

# Workaround a bug in JIT, which responds with error to chatstate
# events without a body
proc chatstate::ignore_error \
     {connid from id type is_subject subject body err thread priority x} {
    switch -- $type/$id {
	error/chatstate {
	    return stop
	}
    }
}

hook::add process_message_hook [namespace current]::chatstate::ignore_error 20

proc chatstate::flush_composing {chatid user body type} {
    variable chatstate

    set chatstate(composing,$chatid) 1
    set chatstate(iscomposing,$chatid) -1
}

hook::add chat_send_message_hook \
    [list [namespace current]::chatstate::flush_composing] 91

proc chatstate::process_x {chatid from type body xs} {
    variable chatstate
    if {$type == "chat"} {
	foreach x $xs {
	    jlib::wrapper:splitxml $x tag vars isempty chdata children
	    set xmlns [jlib::wrapper:getattr $vars xmlns]
	    switch -- $xmlns \
		$::NS(chatstate) {
		    set chatstate(understands,$chatid) 1
		    return [process_x_chatstate \
				$chatid $from $type $body $x]
		}
	}
    }
}

hook::add draw_message_hook \
    [list [namespace current]::chatstate::process_x] 1

proc chatstate::process_x_chatstate {chatid from type body x} {
    variable options
    variable chatstate

    jlib::wrapper:splitxml $x tag vars isempty chdata children
    set chatstate(understands,$chatid) 1
    switch -- $tag {
	active {
	    if {![info exists chatstate(active,$chatid)] || \
		    !$chatstate(active,$chatid)} {
		set chatstate(active,$chatid) 1
		change_status $chatid active
	    }
	}
	inactive {
	    if {[info exists chatstate(active,$chatid)] && \
		    $chatstate(active,$chatid)} {
		set chatstate(active,$chatid) 0
		change_status $chatid inactive
	    }
	}
	gone {
	    set chatstate(active,$chatid) 0
	    change_status $chatid gone
	}
	composing -
	paused {
	    change_status $chatid $tag
	}
    }
    return
}

proc chatstate::change_status {chatid status} {
    variable event_afterid

    if {[info exists event_afterid($chatid)]} {
	after cancel $event_afterid($chatid)
    }
    set cw [chat::winid $chatid]
    set jid [chat::get_jid $chatid]
    set text ""
    set stext ""
    switch -- $status {
	active {
	    set text [::msgcat::mc "Chat window is active"]
	    set stext [format [::msgcat::mc "%s has activated chat window"] $jid]
	}
	composing {
	    set text [::msgcat::mc "Composing a reply"]
	    set stext [format [::msgcat::mc "%s is composing a reply"] $jid]
	}
	paused {
	    set text [::msgcat::mc "Paused a reply"]
	    set stext [format [::msgcat::mc "%s is paused a reply"] $jid]
	}
	inactive {
	    set text [::msgcat::mc "Chat window is inactive"]
	    set stext [format [::msgcat::mc "%s has inactivated chat window"] $jid]
	}
	gone {
	    set text [::msgcat::mc "Chat window is gone"]
	    set stext [format [::msgcat::mc "%s has gone chat window"] $jid]
	}
    }

    if {$stext != "" && $::usetabbar} {set_status $stext}
    if {![winfo exists $cw]} return
    if {$text!=""} {
    	set text2 "[::msgcat::mc "Chat state"]: $text"
	chat::add_message $chatid $jid groupchat $text2 {}
    }
    $cw.status.event configure -text $text
    if {$status!="composing"} {
    set event_afterid($chatid) \
	[after 10000 [list [namespace current]::clear_status $chatid]]
    }
}

proc chatstate::clear_status {chatid} {
    set cw [chat::winid $chatid]
    if {![winfo exists $cw]} return
    $cw.status.event configure -text ""
}

proc chatstate::request_disco {connid jid chatid} {
	variable chatstate
	set chatstate(understands,$chatid) 0
        set vars [list xmlns "http://jabber.org/protocol/disco#info"]
	jlib::send_iq get \
	[jlib::wrapper:createtag query \
	     -vars $vars] \
	-to $jid \
	-connection $connid \
	-command [list [namespace current]::parse_disco \
		       $connid $jid $chatid]
}
proc chatstate::parse_disco {connid jid chatid res child} {
    variable chatstate
    if {![cequal $res OK]} {
	set chatstate(understands,$chatid) 0
	return
    }
    jlib::wrapper:splitxml $child tag vars isempty chdata children
    foreach ch $children {
	jlib::wrapper:splitxml $ch tag1 vars1 isempty1 chdata1 children1
	switch -- $tag1 {
	    feature {
		set var [jlib::wrapper:getattr $vars1 var]
		if {$var == "http://jabber.org/protocol/chatstates"} {
		    set chatstate(understands,$chatid) 1
		    return
		}
	    }
	}
    }
}

proc chatstate::event_composing {chatid sym} {
    variable options
    variable chatstate

    if {![chat::is_chat $chatid]} return
    if {$sym == ""} return


    set connid [chat::get_connid $chatid]
    set jid [chat::get_jid $chatid]

    if {![info exists chatstate(understands,$chatid)]} {
	request_disco $connid $jid $chatid
	return
    }

    if {$chatstate(understands,$chatid)==0} { return }

    if {![info exists chatstate(iscomposing,$chatid)]} {
	    set chatstate(iscomposing,$chatid) 15
	    after 1000 [list [namespace current]::monitor_composing $connid $jid $chatid]
    } else {
	    set chatstate(iscomposing,$chatid) 15
    }

    if {[info exists chatstate(composing,$chatid)] && \
	    !$chatstate(composing,$chatid)} return


    set chatstate(composing,$chatid) 0

    lappend xlist [jlib::wrapper:createtag composing \
		       -vars [list xmlns $::NS(chatstate)]]

    jlib::send_msg $jid -id chatstate -xlist $xlist -connection $connid

}

proc chatstate::monitor_composing {connid jid chatid} {
    variable chatstate
    set iscomp $chatstate(iscomposing,$chatid)
    if {$iscomp==0} {
	    lappend xlist [jlib::wrapper:createtag paused \
	              -vars [list xmlns $::NS(chatstate)]]
	    jlib::send_msg $jid -id chatstate -xlist $xlist -connection $connid
	    set chatstate(composing,$chatid) 1
	    set chatstate(iscomposing,$chatid) -1
    }
    if {$iscomp>0} {
	    set chatstate(iscomposing,$chatid) [expr $iscomp-1]
    }
    after 1000 [list [namespace current]::monitor_composing $connid $jid $chatid]
}

proc chatstate::setup_ui {chatid type} {
    variable chatstate
    global font

    if {![chat::is_chat $chatid]} return

    set cw [chat::winid $chatid]

    set l $cw.status.event
    if {![winfo exists $l]} {
	label $l -font $font
	pack $l -side left
    }

    set iw [chat::input_win $chatid]
    bind $iw <Key> +[list [namespace current]::event_composing \
			 [double% $chatid] %A]
}

hook::add open_chat_post_hook [namespace current]::chatstate::setup_ui

proc chatstate::clear_status_on_send {chatid user body type} {
    if {![chat::is_chat $chatid]} return
    clear_status $chatid
}

hook::add chat_send_message_hook \
    [namespace current]::chatstate::clear_status_on_send

proc chatstate::make_xlist {varname chatid user body type} {
    variable options
    variable chatstate
    variable iscomposing
    upvar 2 $varname var

    if {$type != "chat"} {
	return
    }

    set chatstate(windowactive,$chatid) 1

    lappend var [jlib::wrapper:createtag active \
		     -vars [list xmlns $::NS(chatstate)]]
    set iscomposing 0
    return
}

hook::add chat_send_message_xlist_hook \
    [namespace current]::chatstate::make_xlist

proc chatstate::send_gone {chatid} {
    variable options
    variable chatstate

    if {![info exists chatstate(windowactive,$chatid)] || \
	    ($chatstate(windowactive,$chatid) == 0)} return

    if {![chat::is_chat $chatid]} return

    set connid [chat::get_connid $chatid]
    set jid [chat::get_jid $chatid]

    unset chatstate(windowactive,$chatid)

    lappend xlist [jlib::wrapper:createtag gone \
		       -vars [list xmlns $::NS(chatstate)]]

    jlib::send_msg $jid -id chatstate -xlist $xlist -connection $connid
}

hook::add close_chat_post_hook \
    [namespace current]::chatstate::send_gone 10

